import config from "../../config";
import {
    toastHide,
    toastMessage
} from "../utils/toastUtil.js";
import {
    printInfo,
    printDebug,
    printError,
} from "../utils/printUtil.js"
import {
    appendParam
} from "../utils/util";
import {
    KEY_NOTIFICATION_LOGIN_SUCCESS
} from "../../static/keys/notification-keys.js"

import {
    readToken
} from "./user-service.js"
import {
    gotoLoginPage
} from "./pageRoute.js"
import {
    addNormalNotificationObserver,
    postNotification,
    removeNotificationObserver
} from "../utils/notificationCenter";

const WHITE_LIST = [
    "/getJsCode2Session",
    "/appLogin",
    "/login",
    "/v1/category"
] // 免Token白名单

/**
 * token白名单
 * @param {Object} token token
 * @param {Object} url 请求地址
 */
function checkTokenWhiteList(token, url, urlModule) {
    if (token) return true;
    for (let index = 0; index < WHITE_LIST.length; index++) {
        if (url.startsWith(WHITE_LIST[index])) {
            return true;
        }
    }
    return false;
    return true;
}

/**
 * apiRequest
 */
export let apiRequest = function({
    url = "",
    urlModule = config[`BASE_URL_MODULE`], // 路径识别模块
    data,
    method = 'GET',
    header,
    callback,
    complete
}) {
    let originQuery = {
        ...arguments[0]
    };
    let option = {}; // 请求参数
    // data处理
    if (data) {
        if (typeof data == 'object' && !(data instanceof Array)) { // 对于非 array 的 object 对象， 判断并移除为空的参数
            let dataResult = {};
            Object.keys(data).forEach(key => {
                if (data[key] != null && data[key] != undefined) {
                    dataResult[key] = data[key]
                }
            })
            option.data = dataResult; // 请求数据
        } else { // 其余对象照常插入
            option.data = data;
        }
    }
    // url 处理
    let handlerUrl = `${config["BASE_URL"]}${urlModule?urlModule:""}${url}`;
    if (handlerUrl.indexOf("?") == -1) {
        handlerUrl = `${handlerUrl}?`
        if (method == 'GET') {
            handlerUrl = `${handlerUrl}t=${new Date().getTime()}`
        }
    } else {
        handlerUrl = `${handlerUrl}`
        if (method == 'GET') {
            handlerUrl = `${handlerUrl}&t=${new Date().getTime()}`
        }
    }
    let tempUrl = `${handlerUrl}`;
    if (method == 'GET') {
        console.log(tempUrl, appendParam(option.data, false))
        tempUrl = `${tempUrl}&${appendParam(option.data, false)}`
    }
    option = {
        ...option,
        url: tempUrl,
        method
    }
    // token处理
    let token = readToken();
    if (!checkTokenWhiteList(token, url, urlModule)) {
        if (typeof originQuery.callback == 'function') originQuery.callback(false, null);
        if (typeof originQuery.complete == 'function') originQuery.complete();
        return;
    }
    if (token) {
        option.header = {
            Authorization: `${token}`
        }
    }
    // header处理
    if (header) {
        option.header = {
            ...option.header,
            ...header
        }
    }
    printInfo("start Req", option);
    let requestTask = uni.request({
        ...option,
        success: (res) => {
            successHandler(originQuery, requestTask, res);
        },
        fail: (error) => {
            failHandler(originQuery, requestTask, error);
        },
        complete: (res) => {
            completeHandler(originQuery, requestTask)
        }
    })
    return requestTask;
}

export function apiGET({
    url,
    urlModule = config[`BASE_URL_MODULE`],
    data,
    header,
    callback,
    complete
}) {
    return apiRequest({
        url,
        urlModule,
        data,
        header,
        method: 'GET',
        callback,
        complete
    });
}

export function apiPOST({
    url,
    urlModule = config[`BASE_URL_MODULE`],
    data,
    header,
    callback,
    complete
}) {
    return apiRequest({
        url,
        urlModule,
        data,
        header,
        method: 'POST',
        callback,
        complete
    });
}

export function apiPUT({
    url,
    urlModule = config[`BASE_URL_MODULE`],
    data,
    header,
    callback,
    complete
}) {
    return apiRequest({
        url,
        urlModule,
        data,
        header,
        method: 'PUT',
        callback,
        complete
    });
}

export function apiDELETE({
    url,
    urlModule = config[`BASE_URL_MODULE`],
    data,
    header,
    callback,
    complete
}) {
    return apiRequest({
        url,
        urlModule,
        data,
        header,
        method: 'DELETE',
        callback,
        complete
    });
}

export function apiUPLOAD({
    url = "",
    urlModule = config[`BASE_URL_MODULE`],
    method = "UPLOAD",
    filePath,
    name = "file",
    urlData = {},
    formData = {},
    header,
    callback,
    complete
}) {
    let originQuery = {
        ...arguments[0]
    };
    let option = {}; // 请求参数
    if (filePath) {
        option.filePath = filePath
    }
    if (name) {
        option.name = name
    }
    if (formData) {
        option.formData = formData
    }
    let token = readToken()
    if (!checkTokenWhiteList(token, url, urlModule)) {
        if (typeof originQuery.callback == 'function') originQuery.callback(false, null);
        if (typeof originQuery.complete == 'function') originQuery.complete();
        return;
    }
    option.url = `${config['BASE_URL']}${urlModule?urlModule:""}${url}`;
    if (urlData) {
        option.url = `${option.url}${appendParam(urlData)}`;
    }
    // option.url = `${option.url}?t=${new Date().getTime()}`; // 路径

    if (token) {
        option.header = {
            Authorization: `${token}`
        }
    }
    if (header) {
        option.header = {
            chartset: "utf-8",
            "content-type": "multipart/form-data",
            ...option.header,
            ...header
        }
    } // header
    // console.log(JSON.stringify(option))
    let requestTask = uni.uploadFile({
        ...option,
        success: (res) => {
            successHandler(originQuery, requestTask, res);
        },
        fail: (error) => {
            failHandler(originQuery, requestTask, error)
        },
        complete: () => {
            completeHandler(originQuery, requestTask);
        }
    })
    return requestTask;
}

/**
 * 请求成功处理
 * @param {Object} originQuery 原始请求
 * @param {Object} requestTask 请求任务
 * @param {Object} res 返回数据
 */
let REQUEST_LIST = []
let reQueryWatchFn = function() {
    let watcher = null;
    return function fn(originQuery, requestTask) {
        REQUEST_LIST.push(originQuery);
        if (!watcher) {
            watcher = requestTask;
            addNormalNotificationObserver(KEY_NOTIFICATION_LOGIN_SUCCESS, () => {
                REQUEST_LIST.forEach(queryItem => {
                    if (queryItem.method == 'UPLOAD') {
                        apiUPLOAD(queryItem);
                    } else {
                        apiRequest(queryItem);
                    }
                })
                removeNotificationObserver(KEY_NOTIFICATION_LOGIN_SUCCESS, watcher);
            }, watcher)
        }
    }
}

const app = getApp();

function successHandler(originQuery, requestTask, res) {
    let tokenExpireFn = () => {
        toastHide();
        printDebug("请求结果", originQuery.url, res.data.msg);
        const pages = getCurrentPages();
        if (pages[pages.length - 1].$page.fullPath != "/pages/login/login") {
            if (app.globalData.showLoginWarn) return;
            app.globalData.showLoginWarn = true;
            uni.showModal({
                title: "登录状态已过期",
                content: "当前登录状态已过期，请重新登录！",
                cancelText: "暂不登录",
                confirmText: "前往登录",
                success: (res) => {
                    if (res.confirm) {
                        app.globalData.showLoginWarn = false;
                        gotoLoginPage();
                        reQueryWatchFn()(originQuery, requestTask)
                    } else {
                        app.globalData.showLoginWarn = false;
                        uni.reLaunch({
                            url: "/pages/lesson-list/lesson-list"
                        })
                    }
                }
            })
        }
    }

    if (res.statusCode != 200) {
        toastMessage(`服务器异常,${res.statusCode}`)
        printError("请求失败", originQuery.url, res.errMsg);
        if (typeof originQuery.callback == 'function') originQuery.callback(false, res.statusCode);
    } else {
        let tempData = typeof res.data == 'string' ? JSON.parse(res.data) : res.data
        if (tempData.code == 200) {
            if (typeof originQuery.callback == 'function') originQuery.callback(true, tempData.data);
        } else if (tempData.code == 401) {
            tokenExpireFn();
        } else {
            if (typeof originQuery.callback == 'function') originQuery.callback(false, tempData.message);
        }
    }

}

/**
 * 请求失败处理
 * @param {Object} originQuery 原始请求
 * @param {Object} requestTask 请求任务
 * @param {Object} error 错误
 */
function failHandler(originQuery, requestTask, error) {
    toastMessage("request fail");
    printError("请求--失败", originQuery.url, error.errMsg);
    if (typeof originQuery.callback == 'function') originQuery.callback(false, error.errMsg);
}

/**
 * 请求完成处理
 * @param {Object} originQuery 原始请求
 * @param {Object} requestTask 请求任务
 */
function completeHandler(originQuery, requestTask) {
    if (typeof originQuery.complete == 'function') originQuery.complete();
}
/**
 *  * 
 * // ============= example ============ //
 *      request2Promise(apiGET, {
 *          url: `/order/detail/1570590978977517570`,
 *          data: {
 *              orderRunningId: "1570590978977517570"
 *          }
 *      }).then(res=>{
 *           console.log("promiseTest", res);
 *      }).catch(err=>{
 *          console.log("promiseTest error", err);
 *      });
 * 
 */
/**
 * request 转 promise
 * @param {Function|String} requestFn apiGET/apiPUT/apiPOST/apiDELETE/apiUPLOAD/apiRequest 函数以及支持此类方法相似参数的请求函数，或者 get,post,put,delete,request 字符串（不区分大小写），必须提供一个callback 参数， callback 接受 success 和 data 参数
 * @param {Object} params 参数，参考 apiGET/apiPUT/apiPOST/apiDELETE/apiUPLOAD/apiRequest 参数
 * @returns promise
 */
export function request2Promise(requestFn, params) {
    return new Promise((resolve, reject) => {
        requestFn = get2PromiseRequestFn(requestFn);
        if (!requestFn) {
            toastMessage("请求方法错误");
            reject("请求方法错误");
        } else {
            requestFn({
                ...params,
                callback: (success, data) => {
                    if (success) {
                        resolve(data);
                    } else {
                        reject(data);
                    }
                }
            })
        }
    })
}

/**
 * 2Promise方法处理
 * @param {Function | String} requestFn function 或者 get|post|put|delete|upload|request
 */
function get2PromiseRequestFn(requestFn) {
    if (typeof requestFn == 'function') {
        return requestFn;
    }
    if (typeof requestFn == 'string') {
        requestFn = requestFn.toLowerCase();
        switch (requestFn) {
            case 'get':
                return apiGET;
            case 'post':
                return apiPOST;
            case 'put':
                return apiPUT;
            case "delete":
                return apiDELETE;
            case 'upload':
                return apiUPLOAD;
            case 'request':
                return apiRequest;
            default:
                return null;
        }
    }
    return null;
}